/* 用户信息管理类 */

#pragma once
#include "DataBaseSvr.hpp"

#include <pthread.h>
#include <unordered_map>

// 用户状态枚举
enum UserStatus
{
    OFFLINE,  // 0
    ONLINE  // 1
};

/* 用户信息类 */
struct UserInfo
{
    // 注册调用构造接口
    UserInfo(int userid, const std::string& nickname, const std::string& school, const std::string& telnum, const std::string& passwd)
    {
        _userid = userid;
        _nickname = nickname;
        _school = school;
        _telnum = telnum;
        _passwd = passwd;

        _user_status = OFFLINE;
        _tcp_socket = -1;
        _friend_id.clear();
    }

    UserInfo(){}
    ~UserInfo(){}

    int _userid;
    std::string _nickname;
    std::string _school;
    std::string _telnum;
    std::string _passwd;

    int _user_status;    //该用户状态 OFFLINE/ONLINE
    int _tcp_socket;    //该用户登录客户端对应的套接字描述符
    std::vector<int> _friend_id;    //该用户好友id数组
};


/* 用户管理类 */
class UserManager
{
public:
    UserManager()
    {
        _user_map.clear();
        pthread_mutex_init(&_map_lock, NULL);
        _prepare_id = -1;
        _db = NULL;
    }
    ~UserManager()
    {
        pthread_mutex_destroy(&_map_lock);
        if(_db)
        {
            delete(_db);
            _db = NULL;
        }
    }

    /* 1.初始化对象
     * */
    bool InitUserManager()
    {
        // 1)连接数据库
        _db = new DataBaseSvr();
        if(_db == NULL)
        {
            std::cout << "new DataBaseSvr failed" << std::endl;
            return false;
        }

        if(_db->MysqlInit() == false)
        {
            return false;
        }

        // 2)获取所有用户信息、好友信息
        Json::Value all_us;
        if(_db->GetAllUser(&all_us) == false)
        {
            return false;
        }
        for(int i = 0; i < (int)all_us.size(); ++i)
        {
            // 个人信息
            UserInfo usi;
            usi._userid = all_us[i]["userid"].asInt();
            usi._nickname = all_us[i]["nickname"].asString();
            usi._school = all_us[i]["school"].asString(); 
            usi._telnum = all_us[i]["telnum"].asString();
            usi._passwd = all_us[i]["passwd"].asString();
            usi._user_status = OFFLINE;

            // 好友信息
            _db->GetFriend(usi._userid, &usi._friend_id);

            // 更新_user_map，需加锁
            pthread_mutex_lock(&_map_lock);
            _user_map[usi._userid] = usi;
            pthread_mutex_unlock(&_map_lock);
        }

        // 更新prepare_id，需加锁
        pthread_mutex_lock(&_map_lock);
        _prepare_id = all_us.size();
        pthread_mutex_unlock(&_map_lock);
        
        return true;
    }

    /* 2.处理新用户注册
     *  userid 为出参，注册成功后返回UserManager赋予的id
     * */
    int DearRegister(int* userid, const std::string& nickname, const std::string& school
            , const std::string& telnum, const std::string& passwd)
    {
        // 1)判断注册信息是否合法
        if(nickname.size() == 0 || school.size() == 0 || telnum.size() == 0 || passwd.size() == 0)
        {
            *userid = -2;
            std::cout << "Register user info illeagl !" << std::endl;
            return -1;
        }

        // 2)判断用户是否已存在
        pthread_mutex_lock(&_map_lock);    //加锁
        auto iter = _user_map.begin();
        while(iter != _user_map.end())
        {
            if(iter->second._telnum == telnum)
            {
                *userid = -2;
                pthread_mutex_unlock(&_map_lock);    //解锁
                printf("wrong: user had Register\n");
                return -1;
            }
            iter++;
        }

        // 3)创建UserInfo 分配userid
        UserInfo usi(_prepare_id, nickname, school, telnum, passwd);
        *userid = _prepare_id; 

        _user_map[_prepare_id] = usi;
        _prepare_id++;
        pthread_mutex_unlock(&_map_lock);    //解锁
        
        // 4)更新数据库
        _db->InsertUser(usi._userid, nickname, school, telnum, passwd);

        return true;
    }

    /* 3.处理用户登录
     *  用户通过telnum + passwd 进行登陆
     *  sockfd for 更新用户方套接字信息
     * */
    int DearLogin(const std::string& telnum, const std::string& passwd, int sockfd)
    {
        // 1)判断信息是否合法
        if(telnum.size() == 0 || passwd.size() == 0)
        {
            std::cout << "Login user info illeagl !" << std::endl;
            return -1;
        }

        // 2)判断用户是否已存在
        pthread_mutex_lock(&_map_lock);    //加锁
        auto iter = _user_map.begin();
        while(iter != _user_map.end())
        {
            if(iter->second._telnum == telnum)
            {
                break;
            }
            iter++;
        }
        if(iter == _user_map.end())
        {
            pthread_mutex_unlock(&_map_lock);    //解锁
            return -1;
        }

        // 3)校验用户密码
        if(iter->second._passwd != passwd)
        {
            pthread_mutex_unlock(&_map_lock);    //解锁
            return -1;
        }

        // 4)更新用户：状态、套接字，并返回userid
        iter->second._user_status = ONLINE;
        iter->second._tcp_socket = sockfd;
        int userid = iter->second._userid;
        pthread_mutex_unlock(&_map_lock);    //解锁

        return userid;
    }

    /* 4.获取用户登录状态
     * */
    int IsLogin(int userid)
    {
        pthread_mutex_lock(&_map_lock);    //加锁
        auto iter = _user_map.find(userid);
        if(iter == _user_map.end())
        {
            pthread_mutex_unlock(&_map_lock);    //解锁
            std::cout << "user not existence" << std::endl;
            return -1;
        }
        pthread_mutex_unlock(&_map_lock);    //解锁
        return iter->second._user_status;
    }
    int IsLogin(const std::string& telnum, UserInfo* ui)
    {
        // 1)判断信息是否合法
        if(telnum.size() == 0)
        {
            std::cout << "IsLogin info illeagl !" << std::endl;
            return -1;
        }

        // 2)判断用户是否已存在
        pthread_mutex_lock(&_map_lock);    //加锁
        auto iter = _user_map.begin();
        while(iter != _user_map.end())
        {
            if(iter->second._telnum == telnum)
            {
                break;
            }
            iter++;
        }
        if(iter == _user_map.end())
        {
            pthread_mutex_unlock(&_map_lock);    //解锁
            return -1;
        }
        *ui = iter->second;
        if(iter->second._user_status == OFFLINE)
        {
            pthread_mutex_unlock(&_map_lock);    //解锁
            return OFFLINE;
        }

        pthread_mutex_unlock(&_map_lock);    //解锁
        return ONLINE;
    }

    /* 5.获取单个用户信息
     * */
    bool GetUserInfo(int userid, UserInfo* usi)
    {
        pthread_mutex_lock(&_map_lock);    //加锁
        auto iter = _user_map.find(userid);
        if(iter == _user_map.end())
        {
            pthread_mutex_unlock(&_map_lock);    //解锁
            std::cout << "user not existence" << std::endl;
            return -1;
        }
        *usi = iter->second;
        pthread_mutex_unlock(&_map_lock);    //解锁
        
        return true;
    }

    /* 6.获取用户好友信息
     * */
    bool GetFriends(int userid, std::vector<int>* f_id)
    {
        pthread_mutex_lock(&_map_lock);    //加锁
        auto iter = _user_map.find(userid);
        if(iter == _user_map.end())
        {
            pthread_mutex_unlock(&_map_lock);    //解锁
            std::cout << "user not existence" << std::endl;
            return -1;
        }
        *f_id = iter->second._friend_id;
        pthread_mutex_unlock(&_map_lock);    //解锁
        
        return true;
    }

    /* 7.添加用户好友
     * */
    void setFriend(int userid_1, int userid_2)
    {
        // 1)更新userid1用户的好友列表
        pthread_mutex_lock(&_map_lock);    //加锁
        auto iter = _user_map.find(userid_1);
        if(iter == _user_map.end())
        {
            pthread_mutex_unlock(&_map_lock);    //解锁
            std::cout << "user not existence" << std::endl;
            return;
        }
        iter->second._friend_id.push_back(userid_2);

        // 2)更新userid2用户的好友列表
        iter = _user_map.find(userid_2);
        if(iter == _user_map.end())
        {
            pthread_mutex_unlock(&_map_lock);    //解锁
            std::cout << "user not existence" << std::endl;
            return;
        }
        iter->second._friend_id.push_back(userid_1);
        pthread_mutex_unlock(&_map_lock);    //解锁

        // 3)更新数据库
        _db->InsertFriend(userid_1, userid_2);
        _db->InsertFriend(userid_2, userid_1);
    }

private:
    std::unordered_map<int, UserInfo> _user_map;    //保存所有用户信息的map
    pthread_mutex_t _map_lock;
    
    int _prepare_id;    //预分配ID号
    DataBaseSvr* _db;    //数据库操作类对象指针
};
